;
(function(global, factory) {

	if (typeof define === 'function' && define.amd) {
		// 添加到amd中，并加载依赖
		define([ 'jquery', 'suredy', 'suredyTree', 'bootstrap' ], function(_$, _$d, _t) {
			return factory(global, _$, _$d, _t);
		});
	} else if (!global.jQuery || !global.Suredy || !global.Suredy.Tree) {
		throw new Error("Suredy.Tree requires a jQuery and a Suredy");
	} else {
		factory(global, global.jQuery, global.Suredy, global.Suredy.Tree);
	}

})(this, function(window, $, $d, Tree, undefined) {

	var plugin_flag = '_suredy_tree_selector_';
	var event_node_click = 'suredy.tree.selector.node.click';
	var event_selector_shown = 'suredy.tree.selector.shown';

	// unbind hide event
	$(document).off('click.suredy.tree.selector.hide');

	// bind hide event
	$(document).on('click.suredy.tree.selector.hide', function(event) {
		var target = $(event.target);

		// trigger click
		if (target.hasClass('suredy-tree-selector-trigger'))
			return false;

		// tree click
		if (target.parents('.suredy-tree-selector').length > 0)
			return false;

		$('.suredy-tree-selector-trigger').popover('hide');
	});

	// make tree and bind data
	var _bind_tree_data = function(selector, resource, options) {
		var tree = selector.tree = $(window.document.createElement('div'));
		selector.tree.addClass('tree-container');
		selector.tree.css('overflow', 'auto');

		Tree(tree, resource, options);
	};

	// trigger tree node click
	var _bind_tree_click = function(selector) {
		selector.tree.find('.tree-node').on('suredy.tree.node.click', function() {
			selector.currentNodeClick = this;
			selector.trigger.trigger(event_node_click);
		});
	};

	// after selector shown
	var _bind_selector_show = function(selector) {
		selector.trigger.off('shown.bs.popover');
		// after show, add tree to popover
		selector.trigger.on('shown.bs.popover', function() {
			$(this).trigger(event_selector_shown);
		});
	};

	TreeSelector = function($trigger, resource, options) {
		if (!$trigger || !($trigger instanceof $) || $trigger.length !== 1)
			throw new Error('Need a jQuery(only one) object container.');

		if ($.type(resource) !== 'function' && $.type(resource) !== 'string' && !$.isArray(resource))
			throw new Error('Need a data resource. It can be a function with no params, a url or a array data.');

		return this.prepar($trigger, resource, options);
	};

	TreeSelector.prototype = {
		constructor : TreeSelector,
		prepar : function($trigger, resource, options) {
			this.initedPopover = false;

			this.trigger = $trigger;

			this.trigger.addClass('suredy-tree-selector-trigger');

			this.rect = {
				width : options.width || 'auto',
				height : options.height || 'auto'
			};

			delete options.width;
			delete options.height;

			// off popover
			this.trigger.popover('destroy');

			_bind_tree_data(this, resource, options);

			_bind_tree_click(this);

			_bind_selector_show(this);

			// store data to jQuery
			this.trigger.data(plugin_flag, this);

			return this;
		},
		id : function() {
			return this.trigger.attr('aria-describedby');
		},
		initPopover : function() {
			if (this.initedPopover)
				return false;

			var me = this;

			// init popover
			var maxWidth = 'auto' === this.rect.width ? (this.trigger.outerWidth() + 'px') : this.rect.width;
			var maxHeight = $('body').height() - this.trigger.offset().top - this.trigger.outerHeight() - 5;
			maxHeight = maxHeight < 80 ? 80 : maxHeight;
			maxHeight = 'auto' === this.rect.height ? (maxHeight + 'px') : this.rect.height;
			this.tree.css('max-height', maxHeight);
			this.trigger.popover({
				animation : true,
				content : function() {
					return me.tree;
				},
				html : true,
				placement : 'bottom',
				trigger : 'manual',
				template : '<div class="popover suredy-tree-selector" role="tooltip" style="max-width: ' + maxWidth + '; width: ' + maxWidth + '; margin-top: 0;">\
								<div class="popover-content padding-0">\
								</div>\
							</div>'
			});

			this.initedPopover = true;
		}
	};

	$d.TreeSelector = function(selector, resource, options) {
		if (!selector)
			throw new Error('Error! Need a css selector parameter first.');

		var $trigger = selector;

		if (!($trigger instanceof jQuery))
			$trigger = $(selector);

		if ($trigger.length == 0)
			throw new Error('Error! Can not find selector\'s trigger.');

		return $trigger.each(function(i) {
			var $t = $(this);

			// popover has showed
			if ($t.attr('aria-describedby'))
				$t.popover('destroy');

			new TreeSelector($t, resource, options);

			// off click
			$t.off('.suredy.tree.selector');

			// selecotr.draw();
			$t.on('click.suredy.tree.selector', function() {
				var $this = $(this);

				var component = $this.data(plugin_flag);

				component.initPopover();

				$this.popover('toggle');
			});
		});
	};

	$.extend($d.TreeSelector, {
		nodeClick : event_node_click,
		selectorShown : event_selector_shown,
		hidden : function(selector) {
			if (!selector)
				throw new Error('Invalid Suredy Tree Selector.');

			if (!(selector instanceof jQuery))
				selector = $(selector);

			selector.popover('hide');
		},
		nodes : function(selector) {
			if (!selector)
				throw new Error('Invalid Suredy Tree Selector.');

			if (!(selector instanceof jQuery))
				selector = $(selector);

			var tree = selector.data(plugin_flag).tree;

			return Tree.nodes(tree);
		},
		data : function(node, key) {
			if (!node)
				throw new Error('Invalid Suredy Tree Selector node.');

			if (!(node instanceof jQuery))
				node = $(node);

			// not node. judge it to the selector
			if (!node.hasClass('tree-node')) {
				var comp = node.data(plugin_flag);

				if (!comp)
					throw new Error('It is not a Suredy Tree Selector.');

				node = comp.currentNodeClick;
			}

			// can not find the node, return a empty object
			if (!node)
				return {};

			return Tree.data(node, key);
		},
		checked : function(selector) {
			if (!selector)
				throw new Error('Invalid Suredy Tree Selector.');

			if (!(selector instanceof jQuery))
				selector = $(selector);

			var tree = selector.data(plugin_flag).tree;

			return Tree.checked(tree);
		},
		isActive : function(node) {
			if (!node)
				throw new Error('Invalid Suredy Tree Selector node.');

			if (!(node instanceof jQuery))
				node = $(node);

			// not node. judge it to the selector
			if (!node.hasClass('tree-node')) {
				var comp = node.data(plugin_flag);

				if (!comp)
					throw new Error('It is not a Suredy Tree Selector.');

				node = comp.currentNodeClick;
			}

			// can not find the node, return false
			if (!node)
				return false;

			return Tree.isActive(node);
		},
		setActive : function(node, trigger) {
			if (!node)
				throw new Error('Invalid Suredy Tree Selector node.');

			if (!(node instanceof jQuery))
				node = $(node);

			// not node. judge it to the selector
			if (!node.hasClass('tree-node')) {
				var comp = node.data(plugin_flag);

				if (!comp)
					throw new Error('It is not a Suredy Tree Selector.');

				node = comp.currentNodeClick;
			}

			// can not find the node, return false
			if (!node)
				return false;

			return Tree.setActive(node, trigger);
		}
	});

	$d.TreeSelector.active = $d.TreeSelector.checked;
	$d.TreeSelector.isChecked = $d.TreeSelector.isActive;

	// 对象属性
	$d.TreeSelector.prototype = {
		constructor : $d.TreeSelector
	};

	// 返回Suredy对象
	return $d.TreeSelector;

});